<?php
namespace Core\CoreCommons;

/*
* Logger class definition. This class manage application logs.
*
* @method Logger Singleton()
* @method void Debug($message)
* @method void Info($message)
* @method void Warning($message)
* @method void Error($message)
*/
class Logger 
{
	/**
	* Max size of a log file
	*/
	const FILE_SIZE_MAX = 1000000;
	
	/**
	* @property string $RootPath The root path for all log files
	*/
	private static $RootPath;
	
	/**
	* @property string $CurrentCoreCommonsLog The current core commons log
	*/
	private static $CurrentCoreCommonsLog;
	
	/**
	* @property string $CurrentCoreComponentsLog The current core components log
	*/
	private static $CurrentCoreComponentsLog;
	
	/**
	* @property string $CurrentCoreContractsLog The current contract log
	*/
	private static $CurrentCoreContractsLog;
	
	/**
	* @property string $CurrentDatastorageLog The datastorage log
	*/
	private static $CurrentDatastorageLog;
	
	/**
	* @property string $CurrentCoreLog The current core log
	*/
	private static $CurrentCoreLog;
	
	/**
	* @property Logger $instance The session instance
	*/
	private static $instance;

	/**
	* The singleton instance
	*
	* @return A new Logger instance
	*/
	public static function Singleton() 
	{
		if (!isset(self::$instance) || self::$FilePath == null || self::$FilePath == "") 
		{
			$class = __CLASS__;
			self::$instance = new $class;
		}
		return self::$instance;
	}	
	
	/**
	* Default constructor
	*/
	private function __construct() 
	{
		self::$RootPath = CORE_DIR . "../Logs";
		if(file_exists(self::$RootPath) == false)
		{
			mkdir(self::$RootPath);
		}
	}
	
	/**
	* Debug trace method
	*
	* @param string $message The message to write on the log file
	*/
	public static function Debug($message) 
	{
		$levels = self::ComputeAccessibleLevels();
		if (in_array('Debug', $levels)) 
		{
			$trace = debug_backtrace();
			if(isset($trace[1]))
			{
				$caller = $trace[1];
				$function = $caller['function'];
				$class = $caller['class'];
				
				$file = self::CheckLogFile($class);

				if($file != '')
				{
					$creationDate = date("Y-m-d H:i:s");
					$message = sprintf("Debug [$function] %s : %s", $creationDate, $message);
					self::Write($file, $message);
				}
			}
		}
	}
	
	/**
	* Info trace method
	*
	* @param string $message The message to write on the log file
	*/
	public static function Info($message) 
	{
		$levels = self::ComputeAccessibleLevels();
		if (in_array('Info', $levels)) 
		{
			$trace = debug_backtrace();
			if(isset($trace[1]))
			{
				$caller = $trace[1];
				$function = $caller['function'];
				$class = $caller['class'];
				
				$file = self::CheckLogFile($class);
				
				if($file != '')
				{
					$creationDate = date("Y-m-d H:i:s");
					$message = sprintf("Info [$function] %s : %s", $creationDate, $message);
					self::Write($file, $message);
				}
			}
		}
	}

	/**
	* Warning trace method
	*
	* @param string $message The message to write on the log file
	*/
	public static function Warning($message) 
	{
		$levels = self::ComputeAccessibleLevels();
		if (in_array('Warning', $levels)) 
		{
			$trace = debug_backtrace();
			if(isset($trace[1]))
			{
				$caller = $trace[1];
				$function = $caller['function'];
				$class = $caller['class'];
				
				$file = self::CheckLogFile($class);
				
				if($file != '')
				{
					$creationDate = date("Y-m-d H:i:s");
					$message = sprintf("Warning [$function] %s : %s", $creationDate, $message);
					self::Write($file, $message);
				}
			}
		}
	}
	
	/**
	* Error trace method
	*
	* @param string $message The message to write on the log file
	*/
	public static function Error($message) 
	{
		$levels = self::ComputeAccessibleLevels();
		if (in_array('Error', $levels)) 
		{
			$trace = debug_backtrace();
			if(isset($trace[1]))
			{
				$caller = $trace[1];
				$function = $caller['function'];
				$class = $caller['class'];
				
				$file = self::CheckLogFile($class);
				
				if($file != '')
				{
					$creationDate = date("Y-m-d H:i:s");
					$message = sprintf("Error [$function] %s : %s", $creationDate, $message);
					self::Write($file, $message);
				}
			}
		}
	}
	
	/** 
	* This method have to writer on a log file
	*
	* @param string $message The message to write
	*/
	private static function Write($file, $message)
	{
		$logFile = fopen($file, "a");
		fputs($logFile, $message); 
		fputs($logFile, "\n");
		fclose($logFile);
	}
	
	/** 
	* This method have to create the log file from called class if does'nt exist
	* 1 folder for all components / 1 file by component
	*
	* @param string $class The fullname class
	*
	* @return string The file path
	*/
	private static function CheckLogFile($class)
	{
		self::$RootPath = CORE_DIR . "../Logs";

		if(isset(self::$RootPath) == false || self::$RootPath == '')
		{
			self::$RootPath = CORE_DIR . "../Logs";
		}
		
		if(file_exists(self::$RootPath) == false)
		{
			mkdir(self::$RootPath);
		}
		
		$filePath = '';

		$namespaceParts = explode("\\", $class);

		if(count($namespaceParts) > 0)
		{
			if(isset($namespaceParts[1]) && isset($namespaceParts[2]))
			{
				$service = $namespaceParts[2];
				$folder = self::$RootPath . DIRECTORY_SEPARATOR . $namespaceParts[1];
				
				if(file_exists($folder) == false)
				{
					mkdir($folder);
				}
				
				if(self::StartsWith($namespaceParts[1], "CoreCommons"))
				{
					if(isset(self::$CurrentCoreCommonsLog) == false)
					{
						self::$CurrentCoreCommonsLog = self::CreateLogFile($folder, $service);
					}
					
					$filePath = self ::$CurrentCoreCommonsLog;
					
					if(file_exists($filePath) && filesize($filePath) > self::FILE_SIZE_MAX)
					{
						self ::RecycleLogFile($filePath, $folder, $service);
					}
				}
				else if(self::StartsWith($namespaceParts[1], "CoreComponents"))
				{
					if(isset(self::$CurrentCoreComponentsLog) == false)
					{
						self::$CurrentCoreComponentsLog = self::CreateLogFile($folder, $service);
					}
					
					$filePath = self ::$CurrentCoreComponentsLog;
					
					if(file_exists($filePath) && filesize($filePath) > self::FILE_SIZE_MAX)
					{
						self ::RecycleLogFile($filePath, $folder, $service);
					}
				}
				else if(self::StartsWith($namespaceParts[1], "CoreContracts"))
				{
					if(isset(self::$CurrentCoreContractsLog) == false)
					{
						self::$CurrentCoreContractsLog = self::CreateLogFile($folder, $service);
					}
					
					$filePath = self ::$CurrentCoreContractsLog;
					
					if(file_exists($filePath) && filesize($filePath) > self::FILE_SIZE_MAX)
					{
						self ::RecycleLogFile($filePath, $folder, $service);
					}
				}
				else if(self::StartsWith($namespaceParts[1], "Datastorage"))
				{
					if(isset(self::$CurrentDatastorageLog) == false)
					{
						self::$CurrentDatastorageLog = self::CreateLogFile($folder, $service);
					}

					$filePath = self ::$CurrentDatastorageLog;

					if(file_exists($filePath) && filesize($filePath) > self::FILE_SIZE_MAX)
					{
						self ::RecycleLogFile($filePath, $folder, $service);
					}
				}
			}
			else
			{
				$service = 'ServiceCore';
				$folder = self::$RootPath . DIRECTORY_SEPARATOR . 'Core';
				
				if(file_exists($folder) == false)
				{
					mkdir($folder);
				}
				
				if(isset(self::$CurrentCoreLog) == false)
				{
					self::$CurrentCoreLog = self::CreateLogFile($folder, $service);
				}
				
				$filePath = self ::$CurrentCoreLog;

				if(file_exists($filePath) && filesize($filePath) > self::FILE_SIZE_MAX)
				{
					self ::RecycleLogFile($filePath, $folder, $service);
				}
			}
		}

		return $filePath;
	}
	
	/**
	* Create a log file path
	*
	* @param string $folder The targeted folder
	* @param string $service The service name
	*
	* @return string The log file path
	*/
	private static function CreateLogFile($folder, $service)
	{
		$path = sprintf("$service-%s-%s-%s.log",  date("Y"), date("m"), date("d"));
		return $folder . DIRECTORY_SEPARATOR .$path;
	}
	
	/**
	* This function recycle the big log file which upper than max file size
	*
	* @param string $filePath The log file path
	* @param string $folder The folder name
	* @param string $service The service name
	*/
	private static function RecycleLogFile($filePath, $folder, $service)
	{
		$hour = date("H"). date("i") . date("s");
		$path = sprintf("$service-%s%s%s_%s.log",  date("Y"), date("m"), date("d"), $hour);
		$newName = $folder . DIRECTORY_SEPARATOR .$path;
		rename($filePath, $newName);
	}
	
	/**
	* Compute the accessible levels to write in log file
	*
	* @return array Array which contains allowed levels
	*/
	private static function ComputeAccessibleLevels()
	{
		$parameters = Parameters::Singleton();
		$level = $parameters::Get("logger");
		$levels = array();
		
		switch($level)
		{
			case 'Debug':
				array_push($levels, 'Debug', 'Info', 'Warning', 'Error');
			break;
			case 'Info':
				array_push($levels, 'Info', 'Warning', 'Error');
			break;
			case 'Warning':
				array_push($levels, 'Warning', 'Error');
			break;
			case 'Error':
				array_push($levels, 'Error');
			break;
			default:
				array_push($levels, 'Debug', 'Info', 'Warning', 'Error');
			break;
		}
		
		return $levels;
	}
	
	/**
	* String start with
	*
	* @param string $string the initial string
	* @param string $key the key to find
	*
	* @return boolean True if the key is containing on the string parameter 
	*/
	private static function StartsWith($string, $key)
	{
		return strpos($string, $key) === 0;
	}
}
?> 